home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windows 95 API Bible
/
Windows 95 API Bible 3 Disc Set.iso
/
Win32 API Bible Book 3 of 3
/
CHAPTE20
/
IOPROC.C
< prev
next >
Wrap
C/C++ Source or Header
|
1996-04-29
|
19KB
|
601 lines
#include <windows.h>
#include <io.h>
#include <stdio.h>
#include "IOProc.h"
#if defined (WIN32)
#define IS_WIN32 TRUE
#else
#define IS_WIN32 FALSE
#endif
#define IS_NT IS_WIN32 && (BOOL)(GetVersion() < 0x80000000)
#define IS_WIN32S IS_WIN32 && (BOOL)(!(IS_NT) && (LOBYTE(LOWORD(GetVersion()))<4))
#define IS_WIN95 (BOOL)(!(IS_NT) && !(IS_WIN32S)) && IS_WIN32
HINSTANCE hInst; // current instance
LPCTSTR lpszAppName = "MyApp";
LPCTSTR lpszTitle = "My Application";
// the rest of the stuff
//......................
BOOL RegisterWin95( CONST WNDCLASS* lpwc );
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
MSG msg;
HWND hWnd;
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon (hInstance, lpszAppName);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = lpszAppName;
wc.lpszClassName = lpszAppName;
if ( IS_WIN95 )
{
if ( !RegisterWin95( &wc ) )
return( FALSE );
}
else if ( !RegisterClass( &wc ) )
return( FALSE );
hInst = hInstance;
hWnd = CreateWindow( lpszAppName,
lpszTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0,
CW_USEDEFAULT, 0,
NULL,
NULL,
hInstance,
NULL
);
if ( !hWnd )
return( FALSE );
ShowWindow( hWnd, nCmdShow );
UpdateWindow( hWnd );
while( GetMessage( &msg, NULL, 0, 0) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return( msg.wParam );
}
BOOL RegisterWin95( CONST WNDCLASS* lpwc )
{
WNDCLASSEX wcex;
wcex.style = lpwc->style;
wcex.lpfnWndProc = lpwc->lpfnWndProc;
wcex.cbClsExtra = lpwc->cbClsExtra;
wcex.cbWndExtra = lpwc->cbWndExtra;
wcex.hInstance = lpwc->hInstance;
wcex.hIcon = lpwc->hIcon;
wcex.hCursor = lpwc->hCursor;
wcex.hbrBackground = lpwc->hbrBackground;
wcex.lpszMenuName = lpwc->lpszMenuName;
wcex.lpszClassName = lpwc->lpszClassName;
// Added elements for Windows 95.
//...............................
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.hIconSm = LoadImage(wcex.hInstance, lpwc->lpszClassName,
IMAGE_ICON, 16, 16,
LR_DEFAULTCOLOR );
return RegisterClassEx( &wcex );
}
#define USR_INBLOCK (WM_USER+101)
#define USR_MMIOM_PROC_VERSION (WM_USER+10001)
#define MSG_LEN 1024
#define DATABLOCK_SIZE 300*1024 // 300K
char msg[MSG_LEN+1];
HWND hListBox = NULL;
HWAVEIN hwi;
WAVEHDR wavehdr;
WAVEFORMATEX wfx;
MMRESULT rc;
LPMMIOPROC pIOProc = NULL;
VOID RecordWave(HWND hWnd);
VOID CreateRiff();
LONG CALLBACK WaveIOProc(LPMMIOINFO lpmmioInfo, UINT uMsg,
LPARAM lParam1, LPARAM lParam2);
LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch( uMsg )
{
case WM_CREATE:
// Create ListBox
//...............
hListBox = CreateWindow( "LISTBOX", "",
WS_CHILD | LBS_NOTIFY |
WS_VSCROLL | WS_BORDER |
WS_VISIBLE | LBS_NOINTEGRALHEIGHT,
0, 0,
0, 0,
hWnd,
(HMENU)101,
hInst,
NULL );
// install custom I/O procedure WaveIOProc()
//..........................................
pIOProc = mmioInstallIOProc( (FOURCC)mmioStringToFOURCC("WAV", 0),
(LPMMIOPROC)WaveIOProc, MMIO_INSTALLPROC);
if (!pIOProc)
MessageBox(hWnd, "Install I/O proc failure.", NULL, MB_OK);
// allocate data block
// using only one data block in order to
// keep this example simple
//......................................
wavehdr.lpData = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
DATABLOCK_SIZE);
wavehdr.dwBufferLength = DATABLOCK_SIZE;
break;
case WM_SIZE :
MoveWindow( hListBox, 0, 0,
LOWORD( lParam ),
HIWORD( lParam ), TRUE );
break;
case WM_COMMAND :
switch( LOWORD( wParam ) )
{
case IDM_TEST:
SendMessage(hListBox, LB_RESETCONTENT, 0, 0);
SendMessage(hListBox, LB_ADDSTRING, 0,
(LPARAM)"Recording, please wait...");
// record some wave audio
//.......................
RecordWave(hWnd);
break;
case IDM_ABOUT :
DialogBox( hInst, "AboutBox", hWnd, About );
break;
case IDM_EXIT :
if (hwi)
{
MessageBox(NULL, "Still recording, please wait...",
NULL, MB_OK);
break;
}
DestroyWindow(hWnd);
break;
}
break;
case USR_INBLOCK :
{
// stop recording
//...............
waveInStop(hwi);
waveInReset(hwi);
// Unprepare header
//.................
waveInUnprepareHeader(hwi, &wavehdr, sizeof(WAVEHDR));
waveInClose(hwi);
hwi = NULL;
// create the RIFF file new.wav
//.............................
CreateRiff();
}
break;
case WM_DESTROY:
// free data block
//................
if (wavehdr.lpData)
{
HeapFree(GetProcessHeap(), 0, wavehdr.lpData);
wavehdr.lpData = NULL;
}
// un-install custom I/O procedure WaveIOProc()
//.............................................
mmioInstallIOProc( (FOURCC)mmioStringToFOURCC("WAV ", 0),
(LPMMIOPROC)WaveIOProc, MMIO_REMOVEPROC);
PostQuitMessage(0);
break;
default :
return( DefWindowProc( hWnd, uMsg, wParam, lParam ) );
}
return( 0L );
}
VOID CALLBACK waveInProc( HWAVEIN hwi, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
{
// post message to process this input block received
// NOTE: callback cannot call other waveform functions
//....................................................
if (uMsg == WIM_DATA)
PostMessage((HWND)dwInstance, USR_INBLOCK, 0, dwParam1);
}
VOID RecordWave(HWND hWnd)
{
WAVEINCAPS wic;
hwi = NULL;
rc = waveInGetDevCaps(0, &wic, sizeof(wic));
if (rc == MMSYSERR_NOERROR)
{
wfx.nChannels = wic.wChannels; // use DevCaps # channels
wfx.nSamplesPerSec = 11025; // 11.025 kHz (11.025 * 1000)
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.wBitsPerSample = 8;
wfx.nBlockAlign = wfx.nChannels * wfx.wBitsPerSample / 8;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
wfx.cbSize = 0;
// open waveform input device
//...........................
rc = waveInOpen(&hwi, 0, &wfx, (DWORD)(VOID*)waveInProc, (DWORD)hWnd,
CALLBACK_FUNCTION);
if (rc != MMSYSERR_NOERROR)
{
waveInGetErrorText(rc, msg, MSG_LEN),
MessageBox(hWnd, msg, NULL, MB_OK);
return;
}
}
// prepare buffer block
//.....................
rc = waveInPrepareHeader(hwi, &wavehdr, sizeof(WAVEHDR));
// add buffer to the input queue
if (rc == MMSYSERR_NOERROR)
rc = waveInAddBuffer(hwi, &wavehdr, sizeof(WAVEHDR));
if (rc != MMSYSERR_NOERROR)
{
waveInGetErrorText(rc, msg, MSG_LEN);
waveInClose(hwi);
MessageBox(hWnd, msg, NULL, MB_OK);
return;
}
// start recording
//................
rc = waveInStart(hwi);
}
VOID CreateRiff()
{
HMMIO hmmio; // file handle for open file
MMCKINFO ciRiffChunk; // main RIFF chunk information
MMCKINFO ciSubChunk; // subchunk information
LONG nVersion; // custom I/O proc version
MMIOINFO mmioInfo;
// rename a prev. 'new.wav' file (if one exists)
// to 'new.bak'
//..............................................
mmioRename("new.wav", "new.bak", NULL, 0);
// open the wave file using an internal I/O buffer
//................................................
mmioInfo.dwFlags = 0;
mmioInfo.fccIOProc = mmioStringToFOURCC("WAV ", 0);
mmioInfo.pIOProc = (LPMMIOPROC)WaveIOProc;
mmioInfo.wErrorRet = 0;
mmioInfo.htask = 0;
mmioInfo.cchBuffer = 0;
mmioInfo.pchBuffer = 0;
mmioInfo.pchNext = 0;
mmioInfo.pchEndRead = 0;
mmioInfo.pchEndWrite = 0;
mmioInfo.lBufOffset = 0;
mmioInfo.lDiskOffset = 0;
mmioInfo.adwInfo[0] = 0;
mmioInfo.adwInfo[1] = 0;
mmioInfo.adwInfo[2] = 0;
mmioInfo.adwInfo[3] = 0;
mmioInfo.dwReserved1 = 0;
mmioInfo.dwReserved2 = 0;
mmioInfo.hmmio = 0;
hmmio = mmioOpen("new.wav", &mmioInfo,
MMIO_CREATE | MMIO_WRITE | MMIO_ALLOCBUF);
if(!hmmio)
{
MessageBox(NULL, "Failed to open file.", NULL, MB_OK);
return;
}
// attempt to increase the size of the buffer to 128K
//...................................................
mmioSetBuffer(hmmio, NULL, 131072, 0);
// get customer I/O proc version number and display it
//....................................................
nVersion = mmioSendMessage(hmmio, USR_MMIOM_PROC_VERSION, 0, 0);
sprintf(msg, "Custom I/O procedure version: %ld.%ld installed",
HIWORD(nVersion), LOWORD(nVersion));
SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)msg);
// create main 'RIFF' chunk
//.........................
mmioSeek(hmmio, 0, SEEK_SET); // reset to beginning of file.
ciRiffChunk.fccType = mmioFOURCC('W', 'A', 'V', 'E');
ciRiffChunk.cksize = 0L; // mmio will determine corect size
rc = mmioCreateChunk(hmmio, &ciRiffChunk, MMIO_CREATERIFF);
// create 'fmt' chunk
//...................
ciSubChunk.ckid = mmioStringToFOURCC("fmt ", 0);
ciSubChunk.cksize = sizeof(WAVEFORMATEX);
rc = mmioCreateChunk(hmmio, &ciSubChunk, 0);
rc = mmioWrite(hmmio, (HPSTR)&wfx, sizeof(WAVEFORMATEX));
// ascend out of 'fmt' chunk back to the main 'RIFF' chunk
//........................................................
rc = mmioAscend(hmmio, &ciSubChunk, 0);
// create 'data' chunk
// if the cksize is incorrect, when we ascend out of the chunk,
// the cksize will be updated to it's actual size
//.............................................................
ciSubChunk.ckid = mmioStringToFOURCC("data", 0);
ciSubChunk.cksize = DATABLOCK_SIZE;
rc = mmioCreateChunk(hmmio, &ciSubChunk, 0);
// okay, now lets write the data to the buffer the hard
// way (manually) without the mmioWrite() function.
// The following loop only moves one byte at a time to
// simplify the example.
// If we were going to write the data using the write
// statement, it would look like the following:
// mmioWrite(hmmio, (HPSTR)wavehdr.lpData,
// (LONG)wavehdr.dwBytesRecorded);
//.....................................................
{
LONG i;
mmioGetInfo(hmmio, &mmioInfo, 0);
for (i = 0; i < (LONG)wavehdr.dwBytesRecorded; i++)
{
if (mmioInfo.pchNext == mmioInfo.pchEndWrite)
{
mmioInfo.dwFlags |= MMIO_DIRTY; // we have modified the buffer
mmioAdvance(hmmio, &mmioInfo, MMIO_WRITE);
}
*(mmioInfo.pchNext)++ = (BYTE) *(wavehdr.lpData+i);
}
mmioInfo.dwFlags |= MMIO_DIRTY; // we have modified the buffer
mmioSetInfo(hmmio, &mmioInfo, 0);
}
// ascend out of 'data' chunk back to the main 'RIFF' chunk
// this corrects the chunk length if not correctly
// specified when the chunk was created.
//.........................................................
rc = mmioAscend(hmmio, &ciSubChunk, 0);
// ascend out of the main 'RIFF' chunk
//....................................
rc = mmioAscend(hmmio, &ciRiffChunk, 0);
// flush buffer and close file
//............................
rc = mmioFlush(hmmio, 0);
rc = mmioClose(hmmio, 0);
SendMessage(hListBox, LB_ADDSTRING, 0,
(LPARAM)"RIFF WAVE file 'new.wav' created.");
}
LONG CALLBACK WaveIOProc(LPMMIOINFO lpmmioInfo, UINT uMsg,
LPARAM lParam1, LPARAM lParam2)
{
static int file = 0;
int nFlag;
int nStatus;
LONG lStatus;
switch(uMsg)
{
// Open
//.....
case MMIOM_OPEN:
if (lpmmioInfo->dwFlags & MMIO_READ)
nFlag = OF_READ;
else if (lpmmioInfo->dwFlags & MMIO_WRITE)
nFlag = OF_WRITE;
else if (lpmmioInfo->dwFlags & MMIO_CREATE)
{
file = _lcreat((LPSTR)lParam1, 0);
if (file == -1)
return(MMIOERR_CANNOTOPEN);
else
{
lpmmioInfo->lDiskOffset = 0;
return(0);
}
}
else // default
{
nFlag = OF_READWRITE;
}
file = _lopen((LPSTR)lParam1, nFlag);
if (file == -1)
{
if (lpmmioInfo->dwFlags & MMIO_WRITE)
{
file = _lcreat((LPSTR)lParam1, 0);
}
}
if (file == -1)
return(MMIOERR_CANNOTOPEN);
else
{
lpmmioInfo->lDiskOffset = 0;
return(0);
}
break;
// Close
//......
case MMIOM_CLOSE:
return( _lclose(file) );
// Read
//.....
case MMIOM_READ:
nStatus = _lread(file, (LPSTR)lParam1, (int)lParam2);
lpmmioInfo->lDiskOffset += (int)lParam2;
return( (LONG)nStatus );
// Write
//......
case MMIOM_WRITE:
case MMIOM_WRITEFLUSH:
nStatus = _lwrite(file, (LPSTR)lParam1, (int)lParam2);
lpmmioInfo->lDiskOffset += (int)lParam2;
return( (LONG)nStatus );
// Seek
//.....
case MMIOM_SEEK:
lStatus = _llseek(file, (LONG)lParam1, (int)lParam2);
lpmmioInfo->lDiskOffset = lStatus;
return(lStatus);
// Version (custom message)
//.........................
case USR_MMIOM_PROC_VERSION:
return( MAKELONG(0, 1)); // version 1.00
}
return(0);
}
LRESULT CALLBACK About( HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return (TRUE);
case WM_COMMAND:
if ( LOWORD(wParam) == IDOK
|| LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, TRUE);
return (TRUE);
}
break;
}
return (FALSE);
}